package com.woniu.user.controller;

import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.woniu.user.commons.Result;
import com.woniu.user.config.AlipayConfig;
import com.woniu.user.controller.form.*;
import com.woniu.user.exception.WebException;
import com.woniu.user.exception.WebExceptionCode;
import com.woniu.user.model.Account;
import com.woniu.user.service.AccountService;
import com.woniu.user.service.ChargeService;
import com.woniu.user.service.dto.AccountDto;
import com.woniu.user.util.BeanCopyUtil;
import com.woniu.user.util.JwtUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.math.BigDecimal;
import java.util.Map;

/**
 * <p>
 * 用户账号表（学员和教练） 前端控制器
 * </p>
 *
 * @author Silas
 * @since 2023-02-15
 */
@RestController
@RequestMapping("/account")
@Slf4j
public class AccountController {
    @Resource
    private AccountService accountService;
    @Resource
    private ChargeService chargeService;

    @PostMapping("login")
    public Result login(@RequestBody LoginForm loginForm, HttpServletRequest req) {
        log.info("执行登录操作{}", loginForm);
        Cookie cookie = accountService.login(loginForm);
        // resp.addCookie(cookie);// 响应头加token
        HttpSession session = req.getSession();
        session.setAttribute("token", cookie);
        String type = JwtUtil.getUserTypeFromReq(req);
        System.out.println(type);
        return Result.success(200, "登录成功", type);
    }

    @PostMapping("register")
    public Result register(@RequestBody RegisterForm registerForm) throws MessagingException {
        log.info("执行注册操作{}", registerForm);
        accountService.register(registerForm);
        return Result.success(200, "注册成功", null);
    }

    @SneakyThrows
    @GetMapping("active/{id}")
    public Result active(@PathVariable Integer id, HttpServletResponse resp) {
        log.info("用户激活{}", id);
        accountService.active(id);
        resp.sendRedirect("/user/activeSuccess.html");
        return Result.success(200, "激活成功", null);
    }

    @PostMapping("be")
    public Result beCoach(@RequestBody CoachApplyForm coachApplyForm, HttpServletRequest req) {
        log.info("执行注册成为教练操作{}", coachApplyForm);
        Integer userId = JwtUtil.getUserIdFromReq(req);// 获取用户账号
        accountService.beCoach(userId, coachApplyForm);
        return Result.success(200, "登录成功", null);
    }

    @PostMapping("/modify")
    public Result change(@RequestBody ModifySelfForm modifySelfForm, HttpServletRequest req) {
        log.info("修改个人信息{}", modifySelfForm);
        Integer userId = JwtUtil.getUserIdFromReq(req);// 获取用户账号
        accountService.modifySelf(userId, modifySelfForm);
        return Result.success(200, "修改成功", accountService.getUserInfo(userId));
    }

    @PostMapping("/modifyCoach")
    public Result changeCoach(@RequestBody ModifyCoachForm modifyCoachForm, HttpServletRequest req) {
        log.info("修改教练个人信息{}", modifyCoachForm);
        Integer userId = JwtUtil.getUserIdFromReq(req);// 获取用户账号
        accountService.modifyCoach(userId, modifyCoachForm);
        return Result.success(200, "修改成功", null);
    }

    @PutMapping("changePwd")
    public Result changePwd(@RequestBody ModifyPwdForm form, HttpServletRequest req) {
        log.info("修改密码{}", form);
        Integer userId = JwtUtil.getUserIdFromReq(req);
        accountService.changePwd(userId, form);
        return Result.success(200, "修改成功", "/html/register.html");
    }

    @GetMapping("getMyInfo")
    public Result getMyInfo(HttpServletRequest req) {
        log.info("获取用户个人信息{}", req);
        Integer userId = JwtUtil.getUserIdFromReq(req);
        String userType = JwtUtil.getUserTypeFromReq(req);
        Object userInfo = null;
        if (userType.equals("学员")) {
            userInfo = accountService.getUserInfo(userId);
        } else if (userType.equals("教练")) {
            userInfo = accountService.getCoachInfo(userId);
        }
        return Result.success(200, "查询成功", userInfo);
    }

    // 修改头像
    @PostMapping("fileUpload")
    public Result upload(MultipartFile file, HttpServletRequest req) {
        log.info("上传头像{}", file);
        Integer userId = JwtUtil.getUserIdFromReq(req);
        String url = accountService.updateProfile(file, userId);
        return Result.success(200, "上传成功", url);// 前端刷新页面
    }


    @GetMapping("getStuInfo")
    public Result getStuInfo(HttpServletRequest req) {
        log.info("获取该学员的信息{}", req);
        Integer userId = JwtUtil.getUserIdFromReq(req);
        Account account = accountService.getById(userId);
        if (account == null) throw new WebException(WebExceptionCode.USER_IS_NOT_EXISTS);
        AccountDto accountDto = BeanCopyUtil.copyObject(account, AccountDto.class);
        return Result.success(200, "查询成功", accountDto);
    }

    @PostMapping("wallet")
    public Result wallet(BigDecimal money, HttpServletRequest req) {
        Integer userId = JwtUtil.getUserIdFromReq(req);// 获取用户账号
        log.info("{}提现{}", userId,money);
        Account byId = accountService.getById(userId);
        //余额减去提现金额
        byId.setBalance(byId.getBalance().subtract(money));
        accountService.updateById(byId);
        return Result.success(200, "提现成功", null);
    }

    // 检测邮箱是否已被注册
    @GetMapping("checkEmail")
    public Result checkEmail(String email) {
        log.info("检查邮箱{}", email);
        if (email != null) {
            Account one = accountService.getOne(new QueryWrapper<Account>().eq("email", email));
            if (one != null) return Result.success(200, "该邮箱已被注册", null);
        }
        return null;
    }

    // 发送邮箱验证码（找回密码，redis设置缓存时间）
    @PostMapping("sendCode")
    public Result sendCode(String email) {
        log.info("邮箱找回密码{}", email);
        accountService.sendCode(email);
        return Result.success(200, "发送成功", null);
    }

    // 查询用户余额
    @GetMapping("getBalance")
    public Result getBalance(HttpServletRequest req){
        log.info("查询用户余额{}", req);
        Integer userId = JwtUtil.getUserIdFromReq(req);
        Account account = accountService.getById(userId);
        if (account == null) throw new WebException(WebExceptionCode.USER_IS_NOT_EXISTS);
        BigDecimal balance = account.getBalance();
        return Result.success(200, "查询余额成功", balance.toString());
    }

    // 用户提现
    @PutMapping("cashOut")
    public Result cashOut(@RequestBody CashOutForm form, HttpServletRequest req){
        log.info("用户提现{} {}", form, req);
        Integer userId = JwtUtil.getUserIdFromReq(req);
        try {
            accountService.cashOut(userId, form);
        }catch (WebException e){
            return Result.fail(e.getCode(),e.getMessage());
        }
        return Result.success(200, "提现成功", null);
    }

    // 用户充值
    @PutMapping("cashIn")
    public Result cashIn(BigDecimal money, HttpServletRequest req){
        log.info("用户充值{}, {}", money, req);
        Integer userId = JwtUtil.getUserIdFromReq(req);
        String html = "";
        try {
            html = accountService.cashIn(userId, money);
        }catch (WebException e){
            return Result.fail(e.getCode(), e.getMessage());
        }
        return Result.success(200, "成功", html);
    }

    // 充值 - 支付宝异步回调
    @SneakyThrows
    @PostMapping("alipayCallback")
    public String alipayCallback(HttpServletRequest request){
        // 1.从请求头中取得回调参数
        Map<String, String> parameterMap = accountService.convertParams(request);
        log.info("拿到支付宝返回的参数 {}", parameterMap);
        String outTradeNo = parameterMap.get("out_trade_no");// 获取订单号
        String tradeStatus = parameterMap.get("trade_status");// 获取订单状态
        String amount = parameterMap.get("receipt_amount");// 订单金额

        // 2.验签
        boolean verifySuccess = AlipaySignature.verifyV1(parameterMap, AlipayConfig.alipayPublicKey, AlipayConfig.charset, AlipayConfig.signType);
        if(verifySuccess){
            if(tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED"))
                chargeService.paySuccess(outTradeNo, amount);// 日志已在此方法中打印
            else
                log.warn("订单支付回调结果异常{}, {}", outTradeNo, tradeStatus);
        }else{
            log.warn("支付宝回调验签失败 {}", outTradeNo);
        }

        // 3.向支付宝返回结果 表示已收到回调结果
        return "success";
    }

    // 接收验证码
    @GetMapping("checkCode")
    public Result checkCode(String email, String code) {
        log.info("接收验证码并验证{} {}", email, code);
        accountService.checkCode(email, code);
        return Result.success(200, "收到验证码", null);
    }

    // 重置密码
    @PostMapping("resetPwd")
    public Result resetPwd(@RequestBody RegisterForm registerForm) throws MessagingException {
        log.info("重置密码操作{}", registerForm);
        accountService.resetPwd(registerForm);
        return Result.success(200, "重置成功", null);
    }

}

